package com.partsoft.utils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public abstract class CalendarUtils {
	
	public final static DateFormat xmlDateFormat = new SimpleDateFormat("yyyy-MM-dd");
	
	public final static DateFormat xmlTimeFormat = new SimpleDateFormat("HH:mm");
	
	public final static DateFormat xmlDateTimeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
	
	public final static DateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	
	public final static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
	
	public final static DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
	
	public final static DateFormat idDateTimeFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
	
	private static final InheritableThreadLocal<DateFormatterHelper> _dateFormatHelper = new InheritableThreadLocal<DateFormatterHelper>();
	
	private static DateFormatterHelper getCurrentDateFormatterHelper() {
		DateFormatterHelper helper = (DateFormatterHelper) _dateFormatHelper.get();
		if (helper == null) {
			helper = new DateFormatterHelper();
			_dateFormatHelper.set(helper);
		}
		return helper;
	}
	
	public static String getCaptionByDate(Date date, Locale locale, TimeZone timezone) {
		return getCurrentDateFormatterHelper().getCaptionByDate(date, locale, timezone);
	}
	
	public static String getCaptionByDateOfMonth(Date date, Locale locale, TimeZone timezone) {
		return getCurrentDateFormatterHelper().getCaptionByDateOfMonth(date, locale, timezone);
	}
	
	public static String getCaptionByDayOfWeek(Date date, Locale locale, TimeZone timezone) {
		return getCurrentDateFormatterHelper().getCaptionByDayOfWeek(date, locale, timezone);
	}

	public static String getCaptionByTimeOfDay(Date date, Locale locale, TimeZone timezone) {
		return getCurrentDateFormatterHelper().getCaptionByTimeOfDay(date, locale, timezone);
	}
	
	public static String getCaptionByPopup(Date date, Locale locale, TimeZone timezone) {
		return getCurrentDateFormatterHelper().getCaptionByPopup(date, locale, timezone);
	}
	
	
	public static int getDayOfWeek(Date date, TimeZone timeZone) {
		if (timeZone == null) timeZone = TimeZoneUtils.getCurrent();
		Calendar calendar = Calendar.getInstance(timeZone);
		calendar.setTime(date);
		return calendar.get(Calendar.DAY_OF_WEEK);
	}
	
	public static final int safeCompareTo(Date d1, Date d2) {
		if (d1 == null && d2 == null) return 0;
		if (d1 == null && d2 != null)
			return -1;
		if (d1 != null && d2 == null) return 1;
		
		Date td1 = new Date(d1.getTime());
		Date td2 = new Date(d2.getTime());
		return td1.compareTo(td2);
	}
	
	private static final Date doConvertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone) {
		Assert.notNull(date);
		Assert.notNull(fromTimeZone);
		Assert.notNull(toTimeZone);
		int substract = toTimeZone.getOffset(date.getTime()) - fromTimeZone.getOffset(date.getTime());
		return new Date(date.getTime() + substract);
	}
	
	/**
	 * 转换指定的时区时间至指定的时区时间
	 * @param date
	 * @param fromTimeZone 默认为当前
	 * @param toTimeZone   默认为GMT0
	 * @return
	 */
	public static final Date convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone) {
		Assert.notNull(date);
		if (fromTimeZone == null)
			fromTimeZone = TimeZoneUtils.getCurrent();
		
		if (toTimeZone == null)
			toTimeZone = TimeZoneUtils.getTimeZone(0);
		return doConvertTimeZone(date, fromTimeZone, toTimeZone);
	}
	
	/**
	 * 转换当前系统时区时间至指定的时区
	 * @param date 时间
	 * @param toTimeZone 默认为GMT0时区
	 * @return
	 */
	public static final Date convertTimeZone(Date date, TimeZone toTimeZone) {
		Assert.notNull(date);
		if (toTimeZone == null) return date;
		return CalendarUtils.convertTimeZone(date, TimeZoneUtils.getCurrent(), toTimeZone);
	}
	
	public static final Date now(TimeZone toTimeZone) {
		return CalendarUtils.convertTimeZone(CalendarUtils.now(), 
				TimeZone.getDefault(), toTimeZone);
	}
	
	
	public static final Date round(Date date, int precision) {
		date.setTime(round(date.getTime(), precision));
		return date;
	}
	/**
	 * 把时间进行刻度化
	 *
	 * @param time the date represented in long.
	 * @param precision the divider of the precision(e.g. 10 for precision
	 * of 10 milliseconds;i.e. all millisecond less than 10 would be truncated)
	 * @see #now
	 * @see #round(Date, int)
	 */
	public static final long round(long time, int precision) {
		return time - (time % precision);
	}
	
	public static final int DAY_SCALE = 86400000;
	
	public static final int HOUR_SCALE = 3600000;
	
	public static final int MINUTE_SCALE = 60000;
	
	public static final int SECOND_SCALE = 1000;
	
	/** 
	 * 是否刻度时间
	 */
	public static final boolean isRounded(Date date, int precision) {
		return (date.getTime() % precision) == 0;
	}
	
	/** 
	 * 根据刻度返回日期
	 * @see #round(Date, int)
	 */
	public static final Date now(int precision) {
		return new Date(round(System.currentTimeMillis(), precision));
	}
	/** 
	 * 得到今天
	 */
	public static final Date now() {
		return new Date();
	}
	/** 
	 * 得到今天，不包含小时
	 */
	public static final Date today() {
		return beginOfDate(new Date(), null);
	}

	/**
	 * 得到上一天
	 */
	final public static Date previousDate(Date when) {
		long time = when.getTime() - 24*60*60*1000;
		return new Date(time);
	}

	/**
	 * 得到月的起始日期，默认时区
	 */
	final public static Date beginOfMonth() {
		return beginOfMonth(new Date(), null);
	}
	/**
	 * 得到月的起始日期
	 */
	final public static Date beginOfMonth(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.

		final int year = cal.get(Calendar.YEAR);
		final int month = cal.get(Calendar.MONTH);
		cal.clear();
		cal.set(year, month, 1);
		return cal.getTime();
	}
	
	/**
	 * 得到月的最后时间，默认时区
	 */
	final public static Date endOfMonth() {
		return endOfMonth(new Date(), null);
	}
	/**
	 *得到月的最后时间
	 */
	final public static Date endOfMonth(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.

		final int year = cal.get(Calendar.YEAR);
		final int month = cal.get(Calendar.MONTH);
		final int monthDays = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
		cal.clear();
		cal.set(year, month, monthDays + 1);
		cal.setTimeInMillis(cal.getTimeInMillis() - 1);		
		return cal.getTime();
	}

	/**
	 * 是否月的最后一天
	 */
	final public static boolean isEndOfMonth(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.

		final int day = cal.get(Calendar.DAY_OF_MONTH);
		final int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
		return day == maxDay;
	}


	/**
	 * 得到月的起始时间
	 */
	final public static boolean isBeginOfMonth(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.

		final int day = cal.get(Calendar.DAY_OF_MONTH);
		return day == 1;
	}
	/**
	 * 得到天的起始，默认时区
	 */
	final public static Date beginOfDate(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();

		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime());//don't call cal.setTime(Date) which will reset the TimeZone.
		final int day = cal.get(Calendar.DAY_OF_MONTH);
		final int year = cal.get(Calendar.YEAR);
		final int month = cal.get(Calendar.MONTH);
		cal.clear();
		cal.set(year, month, day);
		
		return cal.getTime();
	}

	/**
	 * 得到天的最后时间
	 */
	final public static Date endOfDate(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();

		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime());//don't call cal.setTime(Date) which will reset the TimeZone.
		final int day = cal.get(Calendar.DAY_OF_MONTH);
		final int year = cal.get(Calendar.YEAR);
		final int month = cal.get(Calendar.MONTH);
		cal.clear();
		cal.set(year, month, day + 1);
		cal.setTimeInMillis(cal.getTimeInMillis() - 1);
		
		return cal.getTime();
	}
	
	/**
	 * 得到年的第一天
	 */
	final public static Date beginOfYear() {
		return beginOfYear(new Date(), null);
	}
	/**
	 * 得到年的第一天
	 */
	final public static Date beginOfYear(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.

		final int year = cal.get(Calendar.YEAR);
		cal.clear();
		cal.set(year, Calendar.JANUARY, 1);
		return cal.getTime();
	}	
	/**
	 * 得到一年的最后一天，默认时间区
	 */
	final public static Date endOfYear() {
		return endOfYear(new Date(), null);
	}
	/**
	 * 得到一年的最后一天
	 */
	final public static Date endOfYear(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.

		final int year = cal.get(Calendar.YEAR);
		cal.clear();
		cal.set(year + 1, Calendar.JANUARY, 1);
		cal.setTimeInMillis(cal.getTimeInMillis() - 1);		
		return cal.getTime();
	}

	/**
	 * Return the ending date of this year.
	 */
	final public static short twoMonthShort() {
		return twoMonthShort(new Date(), null);
	}
	/**
	 * Given a date, a proper TimeZone, return the two month int. eg. 1, 3, 5, 7, 9, 11.
	 * If TimeZone is null, meaning use default TimeZone of the JVM.
	 */
	final public static short twoMonthShort(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.

		final int month = (cal.get(Calendar.MONTH) / 2) * 2 + 1;
		return (short)month;
	}
	
	/**
	 * 得到年
	 * @param when The date.
	 * @param tz The time zone; if null, the current time zone is assumed.
	 * @see #localizedYearOfDate
	 */
	public static final int yearOfDate(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.
		
		return cal.get(Calendar.YEAR);
	}
	
	/**
	 * 得到年本地化的年
	 *
	 * <p>Currenty, only Locale.ZH_TW is supported, i.e.,
	 * "year - 1911" and it's may be less than 0. Otherwise, it is the same
	 * as {@link #yearOfDate}.
	 *
	 * @param when The date.
	 * @param locale the locale; if null, the current locale is assumed.
	 * @param tz The time zone; if null, the current time zone is assumed.
	 * @see #yearOfDate
	 */
	public static final int
	localizedYearOfDate(Date when, Locale locale, TimeZone tz) {
		if (locale == null)
			locale = LocaleUtils.getLocale();

		final int year = yearOfDate(when, tz);
		if (locale.equals(Locale.TAIWAN))
			return year - 1911;
		return year;
	}
	
	/**
	 * 得到月份
	 * @param when The date.
	 * @param tz The time zone; if null, the current time zone is assumed.
	 */
	public static final int monthOfDate(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.
		
		return cal.get(Calendar.MONTH);
	}
	
	/**
	 * +一个月
	 * @param when The date.
	 * @param tz The time zone; if null, the current time zone is assumed.
	 */
	public static final int monthOfDatePlus1(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.
		
		return cal.get(Calendar.MONTH) + 1;
	}
	
	/**
	 * 得到月日期的几天
	 * @param when The date.
	 * @param tz The time zone; if null, the current time zone is assumed.
	 */
	public static final int dayMonthOfDate(Date when, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();
		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime()); //don't call cal.setTime(Date) which will reset the TimeZone.
		
		return cal.get(Calendar.DAY_OF_MONTH);
	}
	
	/**
	 * 添加时间函数
	 * @param when The based date.
	 * @param tz The time zone; if null, the current time zone is assumed.
	 * @param field The time field.
	 * @param amount The amount of date or time to be added to the field.
	 */
	public static final Date add(Date when, TimeZone tz, int field, int amount) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();

		final Calendar cal = Calendar.getInstance(tz);
		cal.setTimeInMillis(when.getTime());//don't call cal.setTime(Date) which will reset the TimeZone.
		
		cal.add(field, amount);
		return cal.getTime();
	}

	/**
	 * 时间相差函数
	 * @param date2 The date2.
	 * @param tz The time zone.
	 * @param field The time field; e.g., Calendar.DATE, Calendar.YEAR, it's default value is Calendar.DATE
	 * @param date1 The date1.
	 */
	public static final long
	subtract(Date date2, TimeZone tz, int field, Date date1) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();

		boolean negative = false;
		if (date1.after(date2)) {
			negative = true;
			final Date d = date1;
			date1 = date2;
			date2 = d;
		}
		
		final Calendar cal1 = Calendar.getInstance(tz);
		cal1.setTimeInMillis(date1.getTime());//don't call cal.setTime(Date) which will reset the TimeZone.

		final Calendar cal2 = Calendar.getInstance(tz);
		cal2.setTimeInMillis(date2.getTime());//don't call cal.setTime(Date) which will reset the TimeZone.
		
		int year1 = cal1.get(Calendar.YEAR);
		int year2 = cal2.get(Calendar.YEAR);
		
		switch(field) {
			case Calendar.YEAR:
			{
				return negative ? (year1-year2) : (year2-year1);
			}
			case Calendar.MONTH:
			{
				int month1 = cal1.get(Calendar.MONTH);
				int month2 = cal2.get(Calendar.MONTH);
				int months = 12 * (year2 - year1) + month2 - month1;
				return negative ? -months : months;
			}
			case Calendar.HOUR:
			{
				long time1 = date1.getTime();
				long time2 = date2.getTime();
				long min1 = (time1 < 0 ? (time1 - (1000 * 60 * 60 - 1)) : time1 ) / (1000 * 60 * 60);
				long min2 = (time2 < 0 ? (time2 - (1000 * 60 * 60 - 1)) : time2 ) / (1000 * 60 * 60);
				return negative ? (min1 - min2) : (min2 - min1);
			}
			case Calendar.MINUTE:
			{
				long time1 = date1.getTime();
				long time2 = date2.getTime();
				long min1 = (time1 < 0 ? (time1 - (1000 * 60 - 1)) : time1 ) / (1000 * 60);
				long min2 = (time2 < 0 ? (time2 - (1000 * 60 - 1)) : time2 ) / (1000 * 60);
				return negative ? (min1 - min2) : (min2 - min1);
			}
			case Calendar.SECOND:
			{
				long time1 = date1.getTime();
				long time2 = date2.getTime();
				long sec1 = (time1 < 0 ? (time1 - (1000 - 1)) : time1 ) / 1000;
				long sec2 = (time2 < 0 ? (time2 - (1000 - 1)) : time2 ) / 1000;
				
				return negative ? (sec1 - sec2) : (sec2 - sec1);
			}
			case Calendar.MILLISECOND:
			{
				return negative ? 
					 (date1.getTime() - date2.getTime()): 
					 (date2.getTime() - date1.getTime());
			}	
			case Calendar.DATE:
			default:	/*default, like -1*/
			{
				int day1 = cal1.get(Calendar.DAY_OF_YEAR);
				int day2 = cal2.get(Calendar.DAY_OF_YEAR);
	
				int maxDay1 = year1 == year2 ? 
					0 : cal1.getActualMaximum(Calendar.DAY_OF_YEAR);
				int days = maxDay1 - day1 + day2;
					
				final Calendar cal = Calendar.getInstance(tz);
				for(int year = year1+1; year < year2; year++) {
					cal.set(Calendar.YEAR, year);
					days += cal.getActualMaximum(Calendar.DAY_OF_YEAR);
				}
				return negative ? -days : days;
			}
		}
	}

	/**
	 * 糅合两个日期时间对象
	 * @param datePart 日期部分
	 * @param timePart 时间部分
	 * @param tz The time zone.
	 */
	public static final Date merge(Date datePart, Date timePart, TimeZone tz) {
		if (tz == null)
			tz = TimeZoneUtils.getCurrent();

		final Calendar dateCal = Calendar.getInstance(tz);
		dateCal.setTimeInMillis(datePart.getTime());//don't call cal.setTime(Date) which will reset the TimeZone.

		final Calendar timeCal = Calendar.getInstance(tz);
		timeCal.setTimeInMillis(timePart.getTime());//don't call cal.setTime(Date) which will reset the TimeZone.
		
		final int hour = timeCal.get(Calendar.HOUR_OF_DAY);
		final int minute = timeCal.get(Calendar.MINUTE);
		final int second = timeCal.get(Calendar.SECOND);
		final int msillisecond = timeCal.get(Calendar.MILLISECOND);
		
		dateCal.set(Calendar.HOUR_OF_DAY, hour);
		dateCal.set(Calendar.MINUTE, minute);
		dateCal.set(Calendar.SECOND, second);
		dateCal.set(Calendar.MILLISECOND, msillisecond);
		
		return dateCal.getTime();
	}
	
	
	public static final Date beginDateOfMonthCalendar(Date curDate, int firstDayOfWeek, TimeZone timezone) {
		if (timezone == null) {
			timezone = TimeZoneUtils.getCurrent();
		}
		if (curDate != null) {
			Calendar cal = Calendar.getInstance(timezone);
			cal.setTime(curDate);
			cal.set(Calendar.DAY_OF_MONTH, 1);
			int index = cal.get(Calendar.DAY_OF_WEEK);
			int offset = index - firstDayOfWeek;
			if (offset < 0) offset += 7;
			cal.add(Calendar.DAY_OF_MONTH, -offset);
			
			cal.set(Calendar.HOUR_OF_DAY, 0);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);
			cal.set(Calendar.MILLISECOND, 0);
			return cal.getTime();
		}
		return null; 
	}
	
	/**
	 * 判断当月份经历过第几个星期？
	 * @param curDate 当前月份的日期
	 * @param firstDayOfWeek 假设一个星期的起始日,<br/>
	 * 例如{@link Calendar#MONDAY}表示星期一是一周的起始日 
	 * @return
	 */
	public static int getWeeksOfMonth(Date curDate, int firstDayOfWeek, TimeZone timezone) {
		if (timezone == null) timezone = TimeZoneUtils.getCurrent();
		Calendar cal = Calendar.getInstance(timezone);
		cal.setTime(curDate);
		int maximun = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
		
		if (cal.getFirstDayOfWeek() != firstDayOfWeek) {			
			cal.set(Calendar.DAY_OF_MONTH, 1);
			int beginIndex = cal.get(Calendar.DAY_OF_WEEK);
			int offset = beginIndex - firstDayOfWeek;
			if (offset < 0)
				offset += 7;
			
			int week = 1;
			int delta = maximun - (7 - offset);
			week += delta/ 7;

			if (delta % 7 != 0) 
				++week;
			return week;
		} else {
			cal.set(Calendar.DAY_OF_MONTH, maximun);
			return cal.get(Calendar.WEEK_OF_MONTH);
		}
	}
	
	public static final Date endDateOfMonthCalendar(Date curDate, int firstDayOfWeek, TimeZone timezon) {
		if (timezon == null) timezon = TimeZoneUtils.getCurrent();
		Date beginDate = beginDateOfMonthCalendar(curDate, firstDayOfWeek, timezon);
		if (beginDate != null) {
			Calendar cal = Calendar.getInstance(timezon);
			int weeks = getWeeksOfMonth(curDate, firstDayOfWeek, timezon);
			cal.setTime(curDate);			
			cal.set(Calendar.DAY_OF_MONTH, 1);
			int offset = cal.get(Calendar.DAY_OF_WEEK) - firstDayOfWeek;
			if (offset < 0)
				offset += 7;
			
			cal.add(Calendar.DAY_OF_MONTH, weeks * 7 - offset);
			cal.set(Calendar.HOUR_OF_DAY, 0);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);	
			cal.set(Calendar.MILLISECOND, 0);
			return cal.getTime();
		}
		return null;
	}
	
	public static final DateFormat getDateFormat(DateFormatType type) {
		return getDateFormat(type, null);
	}
	
	public static final DateFormat getDateFormat(DateFormatType type, TimeZone timeZone) {
		
		if (timeZone == null) timeZone = TimeZoneUtils.getCurrent();
		
		DateFormat dateFormat = null;
		switch (type) {
		case DATEFORMAT:
			return dateFormat;
		case TIMEFORMAT:
			return timeFormat;
		case DATETIMEFORMAT:
			return dateTimeFormat;
		case XML_DATETIMEFORMAT:
			return xmlDateTimeFormat;
		case XML_DATEFORMAT:
			return xmlDateFormat;
		case XML_TIMEFORMAT:
			return xmlTimeFormat;
		default:
			dateFormat = DateFormat.getInstance();
			break;
		}
		dateFormat.setTimeZone(timeZone);
		return dateFormat;
	}
	
	public static String toID(Date date) {
		return idDateTimeFormat.format(date);
	}
	
	public static String toXmlDate(Date date) {
		return xmlDateFormat.format(date);
	}
	
	public static Date fromXmlDate(String xmlDate) throws ParseException {
		return xmlDateFormat.parse(xmlDate);
	}
	
	public static String toXmlTime(Date date) {
		return xmlTimeFormat.format(date);
	}
	
	public static Date fromXmlTime(String xmlTime) throws ParseException {
		return xmlTimeFormat.parse(xmlTime);
	}
	
	public static String toXmlDateTime(Date date) {
		return xmlDateTimeFormat.format(date);
	}
	
	public static Date fromXmlDateTime(String xmlDateTime) throws ParseException {
		return xmlDateTimeFormat.parse(xmlDateTime);
	}
	
	public static String toDateTime(Date date) {
		return dateTimeFormat.format(date);
	}
	
	public static Date toDateTime(String date) throws ParseException {
		return dateTimeFormat.parse(date);
	}
	
	public static Date toDate(String date) throws ParseException {
		return dateFormat.parse(date);
	}
	
	public static class DateFormatterHelper {
		
		private String _dayFormat = "EEE MM/d";
		
		private String _weekFormat = "EEE";
		
		private String _timeFormat = "HH:mm";
		
		private String _ppFormat = "EEE, MMM/d";
		
		private SimpleDateFormat _df, _wf, _tf, _pf;
		
		public String getCaptionByDate(Date date, Locale locale, TimeZone timezone) {
			if (locale == null) locale = LocaleUtils.getLocale();
			if (timezone == null) timezone = TimeZoneUtils.getCurrent();
			if (_df == null) {
				_df = new SimpleDateFormat(_dayFormat, locale);
			}
			_df.setTimeZone(timezone);
			return _df.format(date);
		}
		public String getCaptionByDateOfMonth(Date date, Locale locale, TimeZone timezone) {
			if (locale == null) locale = LocaleUtils.getLocale();
			if (timezone == null) timezone = TimeZoneUtils.getCurrent();

			Calendar cal = Calendar.getInstance();
			cal.setTime(date);
			cal.setTimeZone(timezone);
			if (cal.get(Calendar.DAY_OF_MONTH) == 1) {
				SimpleDateFormat sd = new SimpleDateFormat("MMM d", locale);
				sd.setTimeZone(timezone);
				return sd.format(date);
			}
			return Integer.toString(cal.get(Calendar.DAY_OF_MONTH));
		}

		public String getCaptionByDayOfWeek(Date date, Locale locale, TimeZone timezone) {
			if (locale == null) locale = LocaleUtils.getLocale();
			if (timezone == null) timezone = TimeZoneUtils.getCurrent();

			if (_wf == null) {
				_wf = new SimpleDateFormat(_weekFormat, locale);
			}
			_wf.setTimeZone(timezone);
			return _wf.format(date);
		}

		public String getCaptionByTimeOfDay(Date date, Locale locale, TimeZone timezone) {
			if (locale == null) locale = LocaleUtils.getLocale();
			if (timezone == null) timezone = TimeZoneUtils.getCurrent();

			if (_tf == null) {
				_tf = new SimpleDateFormat(_timeFormat, locale);
			}
			_tf.setTimeZone(timezone);
			return _tf.format(date);
		}
		public String getCaptionByPopup(Date date, Locale locale, TimeZone timezone) {
			if (locale == null) locale = LocaleUtils.getLocale();
			if (timezone == null) timezone = TimeZoneUtils.getCurrent();

			if (_pf == null) {
				_pf = new SimpleDateFormat(_ppFormat, locale);
			}
			_pf.setTimeZone(timezone);
			return _pf.format(date);
		}
	}
	
	
	
	
	/**
	 * 返回当前在年内的时间戳
	 * @param milliseconds time
	 * @return
	 */
	public static int nowTimestampInYearDuring()  {
		return getTimestampInYearDuring(System.currentTimeMillis());
	}
	
	/**
	 * 返回年内的时间戳
	 * @param milliseconds time
	 * @return
	 */
	public static int getTimestampInYearDuring(long milliseconds) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(milliseconds);
		int timestamp = 0;
		timestamp += calendar.get(Calendar.MONTH) + 1;
		timestamp *= 100;

		timestamp += calendar.get(Calendar.DATE);
		timestamp *= 100;

		timestamp += calendar.get(Calendar.HOUR_OF_DAY);
		timestamp *= 100;

		timestamp += calendar.get(Calendar.MINUTE);
		timestamp *= 100;

		timestamp += calendar.get(Calendar.SECOND);
		return timestamp;
	}
	
	public enum DateFormatType {
		
		DATEFORMAT,
		
		XML_DATEFORMAT,
		
		TIMEFORMAT,
		
		XML_TIMEFORMAT,
		
		DATETIMEFORMAT,
		
		XML_DATETIMEFORMAT;
		
	}
	
}
